package main

import "fmt"

/*
Go语言提供了另外一种数据类型：95_接口（interface） 。
他把所有的具有共性的方法定义在一起，任何其他类型只要实现了这些方法就是实现了这些接口。

接口是一组方法签名的集合。然后我们可以定义一个结构体实现该接口的所有方法。因此接口就是定义了对象的行为

接口的主要工作是提供有方法名称，输入参数和返回类型组成的方签名集合。
由类型（例如struct结构体）来声明并实现他们
（如果不在类型上实现了在接口中定义的所有声明方法，则称该类型实现了该接口）
如果一个类型实现了接口中定义的所有声明方法，则称该类型实现了该接口

接口只是一个方法的集合（只是一个概念，只是一个概念上的集合）。
接口中声明的方法的具体实现是基于一个类型的（struct结构体）
如果，实现了定义在某个结构体上的多个方法，而所有这些方法恰好组成个一个接口；那么就说结构体类型实现了该接口

接口是基于类型（9_结构体）实现的。
可以基于很多不同的类型实现这个接口（同样，一个类型也可以实现多个接口）
所以声明一个接口之后要用某个特定的结构体类型来实例化这个接口，（前提是这个特定的机构体类型已经实现了该接口）
然后你就可以用这个接口调用该结构体类型上的所有方法了

定义接口：

type interface_name interface {
	method_name1 [return_type]
	method_name2 [return_type]
	method_name3 [return_type]
...
method_namen [return_type]
}

定义结构体
type struct_name struct {
	variables
}

 在结构体上实现接口方法
func (struct_variable_name struct_name) method_name1() [return_type] {
 方法实现
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
 方法实现
}

说明:
1.接口名：使用type将接口定义为自定义的类型名，Go语言的接口在命名时，一般会在单词后面加er,
	    如果有写操作接口叫Writer,由字符串功能的接口叫Stringer等。接口名最好能够突出几口的类型含义
2.方法名：当方法名首字母是大写且这个接口类型名首字母也是大写，这个方法可以被接口锁在的包（package）之外的代码访问。
3.参数列表：返回值列表:参数列表和返回值列表中的参数变量名可以省略。


*/

type Phone interface {
	call()
}

// 定义结构体
type NokiaPhone struct {
}

// 在结构体 NokiaPhone 上实现接口方法
func (nokiaPhone NokiaPhone) call() {
	fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

// 在结构体 IPhone 上实现接口方法
func (iPhone IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

func main() {
	//声明了一个新的接口phone
	var phone Phone

	//用结构体 NokiaPhone 来实例化接口phone
	//使用 new 函数来为自定义类型分配空间
	phone = new(NokiaPhone)
	//用接口phone调用该结构体上的方法
	phone.call()

	//用结构体 IPhone 来实例化接口phone
	phone = new(IPhone)
	phone.call()

}

/*
接口是什么：
95_接口 定义可一个对选哪个的行为规范，值定义规范不实现，有具体的对象来实现规范的细节。
在Go语言中接口是一种类型一种抽象的类型。
实现接口的条件
一个对象只要全部实现了接口中的方法，那么就实现了这个接口，换句话说，接口就是一个需要实现的接口列表，
接口的实现就是这么简单，只要实现了接口中的所有方法，就实现了这个接口。
*/
